﻿using IronBefunge.Core.InstructionHandlers;
using IronBefunge.Core.Tests.Mocks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace IronBefunge.Core.Tests.InstructionHandlers
{
	[TestClass]
	public sealed class DirectionalInstructionHandlerTests : InstructionHandlerTests
	{
		private static void Handle(char instruction, Direction direction)
		{
			var cells = new List<Cell>() { new Cell(new Point(0, 0), instruction) };
			var stackCount = 0;

			InstructionHandlerTests.Run(new DirectionalInstructionHandler(), cells, (context) =>
			{
				stackCount = context.Values.Count;
			}, (context, result) =>
			{
				Assert.AreEqual(stackCount, context.Values.Count);
				Assert.AreEqual(direction, context.Direction);
			});
		}
	
		[TestMethod]
		public void HandleDown()
		{
			DirectionalInstructionHandlerTests.Handle(
				DirectionalInstructionHandler.DownInstruction, Direction.Down);
		}

		[TestMethod]
		public void HandleLeft()
		{
			DirectionalInstructionHandlerTests.Handle(
				DirectionalInstructionHandler.LeftInstruction, Direction.Left);
		}

		[TestMethod]
		public void HandleRandomDown()
		{
			DirectionalInstructionHandlerTests.Randomizer(Direction.Down);
		}

		[TestMethod]
		public void HandleRandomLeft()
		{
			DirectionalInstructionHandlerTests.Randomizer(Direction.Left);
		}

		[TestMethod]
		public void HandleRandomRight()
		{
			DirectionalInstructionHandlerTests.Randomizer(Direction.Right);
		}

		[TestMethod]
		public void HandleRandomUp()
		{
			DirectionalInstructionHandlerTests.Randomizer(Direction.Up);
		}

		[TestMethod]
		public void HandleRight()
		{
			DirectionalInstructionHandlerTests.Handle(
				DirectionalInstructionHandler.RightInstruction, Direction.Right);
		}

		[TestMethod]
		public void HandleTrampoline()
		{
			var cells = new List<Cell>() { new Cell(
				new Point(0, 0), DirectionalInstructionHandler.TrampolineInstruction) };

			InstructionHandlerTests.Run(new DirectionalInstructionHandler(), cells, null,
				(context, result) =>
				{
					Assert.AreEqual(new Point(0, 1), context.CurrentPosition);
				});
		}

		[TestMethod]
		public void HandleUp()
		{
			DirectionalInstructionHandlerTests.Handle(
				DirectionalInstructionHandler.UpInstruction, Direction.Up);
		}

		private static void Randomizer(Direction direction)
		{
			var cells = new List<Cell>() { new Cell(
				new Point(0, 0), DirectionalInstructionHandler.RandomInstruction) };

			InstructionHandlerTests.Run(new DirectionalInstructionHandler(), cells, null,
				(context, result) =>
				{
					Assert.AreEqual(direction, context.Direction);
				}, new MockSecureRandom(direction));
		}

		internal override ReadOnlyCollection<char> GetExpectedHandledInstructions()
		{
			return new List<char>() { DirectionalInstructionHandler.DownInstruction,
				DirectionalInstructionHandler.LeftInstruction, DirectionalInstructionHandler.RandomInstruction,
				DirectionalInstructionHandler.RightInstruction, DirectionalInstructionHandler.TrampolineInstruction,
				DirectionalInstructionHandler.UpInstruction }.AsReadOnly();
		}

		internal override Type GetHandlerType()
		{
			return typeof(DirectionalInstructionHandler);
		}
	}
}
